package elementsDefense;

import com.jme3.app.SimpleApplication;
import com.jme3.collision.Collidable;
import com.jme3.collision.CollisionResults;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial.CullHint;
import com.jme3.scene.shape.Box;
import com.jme3.util.SafeArrayList;
import elementsDefense.enemies.BasicEnemy;
import elementsDefense.enemies.EnemyWave;
import elementsDefense.gui.HUD;
import java.io.InputStream;
import elementsDefense.map.Map;
import elementsDefense.map.Map.Dir;
import elementsDefense.map.Tile;
import elementsDefense.towers.BasicTower;
import elementsDefense.towers.IceTower;
import elementsDefense.towers.ThunderTower;
import elementsDefense.towers.Tower;
import java.util.ArrayList;
import java.util.LinkedList;

/**
 * test
 * @author normenhansen
 */
public class Main extends SimpleApplication {
    
    
    public static Map map;
    public static Player player;
    public static Vector3f camLocation;
    
    EnemyWave enemyWave;
    //GUI
    HUD hud;
    private SafeArrayList<Collidable> onMouseClickNode = new SafeArrayList<Collidable>(Collidable.class);
    Geometry[][] tiles;
    Geometry selectedTile;
    

    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        initKeys();
        flyCam.setDragToRotate(true);
        flyCam.unregisterInput();
        flyCam.setEnabled(false);
        
        player=new Player();
        
        enemyWave = new EnemyWave(assetManager, rootNode);
        stateManager.attach(enemyWave);
        hud = new HUD(assetManager, guiNode, actionListener, settings.getWidth(), settings.getHeight());
        stateManager.attach(hud);
        
        InputStream in = getClass().getResourceAsStream("/Scenes/map"); 
        try {
            
            map = Map.load(in);
            cam.setLocation(new Vector3f(map.WIDTH/2, 7, map.HEIGHT*1.2f));
            cam.lookAt(new Vector3f(map.WIDTH/2, -1, map.HEIGHT/2), Vector3f.UNIT_Y);
            camLocation=cam.getLocation();
            flyCam.setMoveSpeed(10);
            
            
            Material matStart = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
            matStart.setColor("Color", ColorRGBA.White);
            Material matPAth0 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
            matPAth0.setTexture("ColorMap", assetManager.loadTexture("Textures/path.jpg"));
            Material matPAth2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
            matPAth2.setTexture("ColorMap", assetManager.loadTexture("Textures/path2.jpg"));
            Material matPAth20 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
            matPAth20.setTexture("ColorMap", assetManager.loadTexture("Textures/path20.jpg"));
            Material matPAth22 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
            matPAth22.setTexture("ColorMap", assetManager.loadTexture("Textures/path22.jpg"));
            Material matPAth3 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
            matPAth3.setTexture("ColorMap", assetManager.loadTexture("Textures/path3.jpg"));
            Material matPAth4 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
            matPAth4.setTexture("ColorMap", assetManager.loadTexture("Textures/path4.jpg"));
            Material matEnd = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
            matEnd.setColor("Color", ColorRGBA.Black);
            Material matGrass = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
            matGrass.setTexture("ColorMap", assetManager.loadTexture("Textures/grass.jpg"));
            
            tiles=new Geometry[map.WIDTH][map.HEIGHT];
            for (int y = 0; y < map.HEIGHT; y++) {
                for (int x = 0; x < map.WIDTH; x++) {
                    Box b = new Box(Vector3f.ZERO, 0.5f, 0.01f, 0.5f);
                    Geometry geom = new Geometry(x+":"+y, b);
                    geom.setLocalTranslation(x+0.5f, 0, y+0.5f);
                    if(map.tile[x][y].type==Tile.START) geom.setMaterial(matStart);
                    if(map.tile[x][y].type==Tile.PATH) {
                        LinkedList<Dir> directions=new LinkedList<Dir>();
                        LinkedList<Tile> adjacent=map.adjacentTiles(map.tile[x][y],Tile.PATH|Tile.START|Tile.END,directions);
                        switch(adjacent.size()){
                            case 2:{
                                if(directions.get(0)==Dir.N && directions.get(1)==Dir.S){
                                    geom.setMaterial(matPAth2);
                                    geom.rotate(0, FastMath.HALF_PI, 0);
                                }else if(directions.get(0)==Dir.E && directions.get(1)==Dir.W){
                                    geom.setMaterial(matPAth20);
                                }else{
                                    geom.setMaterial(matPAth22);
                                    if(directions.get(0)==Dir.S && directions.get(1)==Dir.E){
                                        geom.rotate(0, -FastMath.HALF_PI, 0);
                                    }else if(directions.get(0)==Dir.S && directions.get(1)==Dir.W){
                                        geom.rotate(0, FastMath.PI, 0);
                                    }else if(directions.get(0)==Dir.N && directions.get(1)==Dir.W){
                                        geom.rotate(0, FastMath.HALF_PI, 0);
                                    }
                                }
                                break;}
                            case 3:{
                                geom.setMaterial(matPAth3);
                                    if(directions.get(0)==Dir.S && directions.get(1)==Dir.E && directions.get(2)==Dir.W){
                                        geom.rotate(0, -FastMath.HALF_PI, 0);
                                    }else if(directions.get(0)==Dir.N && directions.get(1)==Dir.S && directions.get(2)==Dir.W){
                                        geom.rotate(0, FastMath.HALF_PI, 0);
                                    }else if(directions.get(0)==Dir.N && directions.get(1)==Dir.S && directions.get(2)==Dir.E){
                                        geom.rotate(0, -FastMath.HALF_PI, 0);
                                    }
                                break;}
                            case 4:{geom.setMaterial(matPAth4);break;}
                            default:geom.setMaterial(matPAth0);
                        }
                    }
                    if(map.tile[x][y].type==Tile.END) geom.setMaterial(matEnd);
                    if(map.tile[x][y].type==Tile.GRASS) geom.setMaterial(matGrass);
                    rootNode.attachChild(geom);
                    onMouseClickNode.add(geom);
                    tiles[x][y]=geom;
                }
            }
            selectedTile = new Geometry("selectedTile", new Box(Vector3f.ZERO, 0.5f, 0.5f, 0.5f));
            Material matSelect = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
            matSelect.setTexture("ColorMap", assetManager.loadTexture("Textures/select.png"));
            matSelect.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
            selectedTile.setMaterial(matSelect);
            selectedTile.setQueueBucket(Bucket.Transparent);
            selectedTile.setCullHint(CullHint.Always);
            rootNode.attachChild(selectedTile);
            
        } catch (Exception ex) {
            ex.printStackTrace();
            System.exit(-1);
        }
        
        player.set(100, 100);
    }
    
    @Override
    public void simpleUpdate(float tpf) {
        
    }

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }
    
    
    
    private void initKeys() {
        // You can map one or several inputs to one named action
        inputManager.clearMappings();
        inputManager.addMapping("mouse_button_right", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        // Add the names to the action listener.
        inputManager.addListener(actionListener, new String[]{"mouse_button_right"});

    }
    int currentTileX,currentTileY;
    private ActionListener actionListener = new ActionListener() {
        public void onAction(String name, boolean isPressed, float tpf) {
            if (name.equals("mouse_button_right") && isPressed) {
                Vector2f click2d = inputManager.getCursorPosition();
                //check GUI interaction
                if(!hud.testEvent((int)click2d.x, (int)click2d.y, isPressed)){
                    // Reset results list.
                    CollisionResults results = new CollisionResults();
                    // Convert screen click to 3d position
                    Vector3f click3d = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 0f).clone();
                    Vector3f dir = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d).normalizeLocal();
                    // Aim the ray from the clicked spot forwards.
                    Ray ray = new Ray(click3d, dir);
                    // Collect intersections between ray and all nodes in results list.
                    results = collide(ray, onMouseClickNode);

                    // Use the results 
                    if (results.size() > 0) {
                        // The closest result is the target that the player picked:
                        String key = results.getClosestCollision().getGeometry().getName();
                        String[] ses = key.split(":");
                        currentTileX = Integer.parseInt(ses[0]);//http://www.majorleaguegaming.com/live#event=twitch&streams=lol
                        currentTileY = Integer.parseInt(ses[1]);
                        selectedTile.setLocalTranslation(currentTileX+0.5f, 0.51f, currentTileY+0.5f);
                        selectedTile.setCullHint(CullHint.Inherit);
                        hud.towerDialog.show((int)click2d.x, (int)click2d.y);
                    }else{ //Clear selection
                        selectedTile.setCullHint(CullHint.Always);
                        hud.towerDialog.hide();
                    }
                }
            } else if(name.equals("iceTower")){
                Tower iceTower = new IceTower();
                iceTower.build(assetManager, rootNode, tiles[currentTileX][currentTileY].getLocalTranslation());
                hud.towerDialog.hide();
                selectedTile.setCullHint(CullHint.Always);
            } else if(name.equals("canonTower")){
                Tower basicTower = new BasicTower();
                basicTower.build(assetManager, rootNode, tiles[currentTileX][currentTileY].getLocalTranslation());
                hud.towerDialog.hide();
                selectedTile.setCullHint(CullHint.Always);
            } else if(name.equals("thunderTower")){
                Tower thunderTower = new ThunderTower();
                thunderTower.build(assetManager, rootNode, tiles[currentTileX][currentTileY].getLocalTranslation());
                hud.towerDialog.hide();
                selectedTile.setCullHint(CullHint.Always);
            } 
        }
    };
    
    public CollisionResults collide( Collidable ray, SafeArrayList<Collidable> objects){
        CollisionResults results = new CollisionResults();
        for (Collidable child : objects.getArray()){
            child.collideWith(ray, results);
        }
        return results;
    }
    
}
